#-*- coding:utf-8 -*-
from Crypto.Cipher import AES
import re, random, string
import threading
import random
import socket
import base64
import time
import os

AES_Key = '89MB5rkH6ZM3GLPA'
Base_path = ".\\Base\\"
Programs = ".\\Program\\"
Login_s = []

def Pass_16():
    src = string.ascii_letters + string.digits
    count = 1
    list_passwds = []
    for i in range(int(count)):
        list_passwd_all = random.sample(src, 16)
        list_passwd_all.extend(random.sample(string.digits, 1))
        list_passwd_all.extend(random.sample(string.ascii_lowercase, 1))
        list_passwd_all.extend(random.sample(string.ascii_uppercase, 1))
        random.shuffle(list_passwd_all)
        str_passwd = ''.join(list_passwd_all)
        if str_passwd not in list_passwds:
            list_passwds.append(str_passwd)
        return(list_passwds[0])

def AES_encode(data, key):
    while len(data) % 16 != 0:
        data += (16 - len(data) % 16) * chr(16 - len(data) % 16)
    data = str.encode(data)
    aes = AES.new(str.encode(key), AES.MODE_ECB)
    return str(base64.encodebytes(aes.encrypt(data)), encoding='utf8').replace('\n', '')


def AES_decode(data, key):
    aes = AES.new(str.encode(key), AES.MODE_ECB)
    decrypted_text = aes.decrypt(base64.decodebytes(bytes(data, encoding='utf8'))).decode("utf8")
    decrypted_text = decrypted_text[:-ord(decrypted_text[-1])]
    return(decrypted_text)

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.connect(('8.8.8.8', 80))
    ip = s.getsockname()[0]
finally:
    s.close()
print(ip)#

def re(number, key = False):
    if key == False:
        number = str(number).encode()
        return(number)
    else:
        number = str(number)
        return(AES_encode(number, key).encode())

def config(search, path = "login_co.cot") :
    if os.path.exists(path) == False:
        return(None)
    for line in open(path) :
        if line[-1:] == "\n" :
            line = line[:-1]
        if "=" in line :
            sc = line.split('=',1)[0].strip()
            data = line.split('=',1)[1].strip()
            if search == sc :
                if data == "_None" :
                    return(" ")
                else :
                    return(data)
            else :
                del sc,data
    return(None)

def TCP(port, user, ip, key):
    global Login_s
    Bases = []
    Programs = []
    c = socket.socket()
    c.bind((ip, port))
    c.listen()
    conn, addr = c.accept()
    print('User ' + user + ' login at Port.' + str(port))
    data = conn.recv(1024).decode()
    if data == '100':
        conn.send(re(300))
        while True :
            try :
                data = conn.recv(1024).decode()
                #--100
                if data == '100':
                    conn.send(re(300))
                #--140
                elif data[0:3] == '140':
                    data = data.split('-')
                    if len(data) == 3:
                        Base = data[1]
                        Key = data[2]
                        if os.path.exists(Base_path + Base) == True:
                            if user in config(Base, ".\\Base\\Base-rights.cot"):
                                if config(Base, ".\\Base\\Base-key.cot") == Key:
                                    Bases.append(Base)
                                    conn.send(re(300))
                                else:
                                    conn.send(re(303))
                            else:
                                conn.send(re(313)) 
                        else:
                            conn.send(re(315))
                    else:
                        conn.send(re(309))
                #--141
                elif data[0:3] == '141':
                    data = data.split('-')
                    if len(data) == 3:
                        Base = data[1]
                        path = data[2]
                        if Base in Bases:
                            Base = Base_path + Base + path
                            if os.path.exists(Base) == True:
                                data = str(os.listdir(Base)).encode()
                                conn.send(data)
                            else:
                                conn.send(re(315))
                        else:
                            conn.send(re(314))
                    else:
                        conn.send(re(309))
                else:
                    conn.send(re(308))
            except :
                break
    c.close()
    print(user + ' exit')
    Login_s.remove(user)

def TCP_IOT(port, user, ip):
    global Login_s
    Bases = []
    Programs = []
    c = socket.socket()
    c.bind((ip, port))
    c.listen()
    conn, addr = c.accept()
    print('Iot ' + user + ' login at Port.' + str(port))
    data = conn.recv(1024).decode()
    if data == '100':
        conn.send(re(300))
        while True :
            try :
                data = conn.recv(1024).decode()
                #--100
                if data == '100':
                    conn.send(re(300))
                #--140
                elif data[0:3] == '140':
                    data = data.split('-')
                    if len(data) == 3:
                        Base = data[1]
                        Key = data[2]
                        if os.path.exists(Base_path + Base) == True:
                            if user in config(Base, ".\\Base\\Base-rights.cot"):
                                if config(Base, ".\\Base\\Base-key.cot") == Key:
                                    Bases.append(Base)
                                    conn.send(re(300))
                                else:
                                    conn.send(re(303))
                            else:
                                conn.send(re(313)) 
                        else:
                            conn.send(re(315))
                    else:
                        conn.send(re(309))
                #--141
                elif data[0:3] == '141':
                    data = data.split('-')
                    if len(data) == 3:
                        Base = data[1]
                        path = data[2]
                        if Base in Bases:
                            Base = Base_path + Base + path
                            if os.path.exists(Base) == True:
                                data = str(os.listdir(Base)).encode()
                                conn.send(data)
                            else:
                                conn.send(re(315))
                        else:
                            conn.send(re(314))
                    else:
                        conn.send(re(309))
                #--1461
                elif data[0:4] == '1461':
                    data = data.split("-")
                    i = config(user, "io_update.cot").split("-")
                    if i[0] in Bases:
                        with open(".\\Base" + i[1] + data[1]) as f:
                            conn.send(f.read().encode())
                    else:
                        conn.send(re(313))
                else:
                    conn.send(re(308))
            except :
                break
    c.close()
    print(user + ' exit')
    Login_s.remove(user)

server = socket.socket()
server.bind((ip, 1030))
server.listen()
while True :
    conn, addr = server.accept()
    while True :
        try :
            data = conn.recv(1024).decode()
            
        except :
            break
        try:
            print(data)
            if data[0:4] == '1131':
                data = data.split('-')
                if len(data) == 3:
                    user = data[1]
                    key = data[2]
                    if key == config(user, "login_io.cot") and user not in Login_s:
                        port = random.randint(1050,50000)
                        command = '-' + str(port)
                        A = threading.Thread(target=TCP_IOT,args=(port, user, ip,)) 
                        A.start()
                        Login_s.append(user)
                        conn.send(re(200) + command.encode())
                        conn.close()
                    else:
                        conn.send(re(201))
            data = AES_decode(data, AES_Key)
            if data[0:3] == '113-':
                data = data.split('-')
                if len(data) == 3:
                    user = data[1]
                    key = data[2]
                    if key == config(user) and user not in Login_s:
                        port = random.randint(1050,50000)
                        AES_k = Pass_16()
                        command = '-' + str(port) + '-' + AES_k
                        A = threading.Thread(target=TCP,args=(port, user, ip, AES_k,)) 
                        A.start()
                        Login_s.append(user)
                        conn.send(re(200) + command.encode())
                        conn.close()
                    else:
                        conn.send(re(201))
                else:
                    conn.send(re(309))
            else:
                conn.send(re(308))
        except:
            pass
